---
title: 音声エージェントの構築
description: Learn how to build voice agents using the OpenAI Agents SDK, what features are available, how to architecture your application, and more.
---

import { Steps, Aside, Code } from '@astrojs/starlight/components';
import createAgentExample from '../../../../../../../examples/docs/voice-agents/createAgent.ts?raw';
import multiAgentsExample from '../../../../../../../examples/docs/voice-agents/multiAgents.ts?raw';
import createSessionExample from '../../../../../../../examples/docs/voice-agents/createSession.ts?raw';
import configureSessionExample from '../../../../../../../examples/docs/voice-agents/configureSession.ts?raw';
import handleAudioExample from '../../../../../../../examples/docs/voice-agents/handleAudio.ts?raw';
import defineToolExample from '../../../../../../../examples/docs/voice-agents/defineTool.ts?raw';
import toolApprovalEventExample from '../../../../../../../examples/docs/voice-agents/toolApprovalEvent.ts?raw';
import guardrailsExample from '../../../../../../../examples/docs/voice-agents/guardrails.ts?raw';
import guardrailSettingsExample from '../../../../../../../examples/docs/voice-agents/guardrailSettings.ts?raw';
import audioInterruptedExample from '../../../../../../../examples/docs/voice-agents/audioInterrupted.ts?raw';
import sessionInterruptExample from '../../../../../../../examples/docs/voice-agents/sessionInterrupt.ts?raw';
import sessionHistoryExample from '../../../../../../../examples/docs/voice-agents/sessionHistory.ts?raw';
import historyUpdatedExample from '../../../../../../../examples/docs/voice-agents/historyUpdated.ts?raw';
import updateHistoryExample from '../../../../../../../examples/docs/voice-agents/updateHistory.ts?raw';
import customWebRTCTransportExample from '../../../../../../../examples/docs/voice-agents/customWebRTCTransport.ts?raw';
import websocketSessionExample from '../../../../../../../examples/docs/voice-agents/websocketSession.ts?raw';
import transportEventsExample from '../../../../../../../examples/docs/voice-agents/transportEvents.ts?raw';
import thinClientExample from '../../../../../../../examples/docs/voice-agents/thinClient.ts?raw';
import toolHistoryExample from '../../../../../../../examples/docs/voice-agents/toolHistory.ts?raw';
import sendMessageExample from '../../../../../../../examples/docs/voice-agents/sendMessage.ts?raw';
import serverAgentExample from '../../../../../../../examples/docs/voice-agents/serverAgent.ts?raw';
import delegationAgentExample from '../../../../../../../examples/docs/voice-agents/delegationAgent.ts?raw';
import turnDetectionExample from '../../../../../../../examples/docs/voice-agents/turnDetection.ts?raw';

## 音声の処理

デフォルトの `OpenAIRealtimeWebRTC` のような一部のトランスポート層は、音声の入力と出力を自動的に処理します。`OpenAIRealtimeWebSocket` のような他のトランスポート機構では、セッションの音声を自分で処理する必要があります。

<Code lang="typescript" code={handleAudioExample} />

## セッションの設定

[`RealtimeSession`](/openai-agents-js/openai/agents-realtime/classes/realtimesession/) のコンストラクターに追加のオプションを渡すか、`connect(...)` を呼び出す際にオプションを渡すことで、セッションを設定できます。

<Code lang="typescript" code={configureSessionExample} />

これらのトランスポート層では、[session](https://platform.openai.com/docs/api-reference/realtime-client-events/session/update) に一致する任意のパラメーターを渡せます。

[RealtimeSessionConfig](/openai-agents-js/openai/agents-realtime/type-aliases/realtimesessionconfig/) に存在しない新しいパラメーターについては、`providerData` を使用できます。`providerData` に渡したものは、`session` オブジェクトの一部としてそのまま渡されます。

## ハンドオフ

通常のエージェントと同様に、ハンドオフを使ってエージェントを複数に分割し、それらの間をオーケストレーションすることで、エージェントのパフォーマンスを向上させ、問題のスコープを適切に絞ることができます。

<Code lang="typescript" code={multiAgentsExample} />

通常のエージェントと異なり、リアルタイムエージェントではハンドオフの挙動が少し異なります。ハンドオフが実行されると、進行中のセッションは新しいエージェント構成で更新されます。このため、エージェントは進行中の会話履歴に自動的にアクセスでき、現在は入力フィルターは適用されません。

さらに、これによりハンドオフの一部として `voice` や `model` を変更することはできません。また、接続できるのは他の リアルタイムエージェント のみです。別のモデル、たとえば `gpt-5-mini` のような推論モデルを使用する必要がある場合は、[ツールによる委譲](#delegation-through-tools) を使用できます。

## ツール

通常のエージェントと同様に、リアルタイムエージェント はアクションを実行するためにツールを呼び出せます。通常のエージェントで使用するのと同じ `tool()` 関数でツールを定義できます。

<Code lang="typescript" code={defineToolExample} />

リアルタイムエージェント で使用できるのは 関数ツール のみで、これらのツールはあなたの Realtime Session と同じ場所で実行されます。つまり、Realtime Session をブラウザで実行している場合、ツールもブラウザで実行されます。よりセンシティブな操作が必要な場合は、ツール内からバックエンド サーバー への HTTP リクエストを行ってください。

ツールの実行中、エージェントは ユーザー からの新規リクエストを処理できません。体験を向上させる方法として、ツールを実行しようとしていることを事前にエージェントにアナウンスさせたり、ツール実行のための時間を稼ぐ特定のフレーズを話させたりできます。

### 会話履歴へのアクセス

エージェントが特定のツールを呼び出した際の引数に加えて、Realtime Session によって追跡される現在の会話履歴のスナップショットにもアクセスできます。これは、会話の現在の状態に基づいてより複雑なアクションを実行する必要がある場合や、[委譲のためのツール](#delegation-through-tools) を使用する予定がある場合に有用です。

<Code lang="typescript" code={toolHistoryExample} />

<Aside type="note">
  渡される履歴は、ツール呼び出し時点のスナップショットです。ユーザーが最後に話した内容の書き起こしは、まだ利用できない可能性があります。
</Aside>

### ツール実行前の承認

`needsApproval: true` でツールを定義すると、エージェントはツールを実行する前に `tool_approval_requested` イベントを発行します。

このイベントをリッスンすることで、ツール呼び出しを承認または拒否するための UI を ユーザー に表示できます。

<Code lang="typescript" code={toolApprovalEventExample} />

<Aside type="note">
  音声エージェント がツール呼び出しの承認待ちの間、エージェントは ユーザー
  からの新規リクエストを処理できません。
</Aside>

## ガードレール

ガードレール は、エージェントの発話が特定のルールに違反していないかを監視し、即座にレスポンスを打ち切る仕組みを提供します。これらの ガードレール チェックはエージェントの応答の書き起こしに基づいて実行されるため、モデルのテキスト出力が有効である必要があります（デフォルトで有効）。

提供した ガードレール は、モデルのレスポンスが返るのと同時に非同期に実行され、例えば「特定の禁止語を言及した」など、あらかじめ定義した分類トリガーに基づいてレスポンスを打ち切れます。

ガードレール が作動すると、セッションは `guardrail_tripped` イベントを発行します。イベントには、ガードレール をトリガーした `itemId` を含む `details` オブジェクトも提供されます。

<Code lang="typescript" code={guardrailsExample} />

デフォルトでは、ガードレール は 100 文字ごと、またはレスポンステキストの生成完了時に実行されます。テキストの読み上げには通常時間がかかるため、ほとんどの場合、ユーザーが聞く前に ガードレール が違反を検知できます。

この挙動を変更したい場合は、`outputGuardrailSettings` オブジェクトをセッションに渡してください。

<Code lang="typescript" code={guardrailSettingsExample} />

## ターン検出 / 音声活動検出

Realtime Session は、ユーザーが話しているタイミングを自動的に検出し、組み込みの [Realtime API の音声活動検出モード](https://platform.openai.com/docs/guides/realtime-vad) を使用して新しいターンをトリガーします。

`turnDetection` オブジェクトをセッションに渡すことで、音声活動検出モードを変更できます。

<Code lang="typescript" code={turnDetectionExample} />

ターン検出の設定を調整することで、望ましくない割り込みや無音への対処をキャリブレーションできます。各種設定の詳細は [Realtime API ドキュメント](https://platform.openai.com/docs/guides/realtime-vad) を参照してください

## 割り込み

組み込みの音声活動検出を使用している場合、エージェントの発話に被せて話すと、自動的にエージェントが発話内容を検知し、コンテキストを更新します。また、`audio_interrupted` イベントを発行します。これはすべての音声再生を即座に停止するために使用できます（WebSocket 接続にのみ適用）。

<Code lang="typescript" code={audioInterruptedExample} />

UI に「停止」ボタンを用意するなど、手動で割り込みを行いたい場合は、`interrupt()` を手動で呼び出せます。

<Code lang="typescript" code={sessionInterruptExample} />

いずれの場合も、Realtime Session はエージェントの生成を割り込み、ユーザーに話した内容の認識を切り詰め、履歴を更新します。

WebRTC を使用してエージェントに接続している場合は、音声出力もクリアされます。WebSocket を使用している場合は、再生キューに入っている音声の再生停止を自分で処理する必要があります。

## テキスト入力

エージェントにテキスト入力を送信したい場合は、`RealtimeSession` の `sendMessage` メソッドを使用します。

これは、エージェントとのやり取りを両方のモダリティで ユーザー に許可したい場合や、会話に追加のコンテキストを提供したい場合に有用です。

<Code lang="typescript" code={sendMessageExample} />

## 会話履歴の管理

`RealtimeSession` は、`history` プロパティで会話履歴を自動的に管理します。

これを使用して、顧客に履歴を表示したり、追加の処理を行ったりできます。会話の進行中は履歴が継続的に変化するため、`history_updated` イベントをリッスンできます。

履歴を変更したい場合（メッセージを完全に削除したり、その書き起こしを更新したりするなど）は、`updateHistory` メソッドを使用できます。

<Code lang="typescript" code={updateHistoryExample} />

### 制限事項

1. 現在、後から 関数ツール 呼び出しを更新/変更することはできません
2. 履歴内のテキスト出力には、トランスクリプトとテキストモダリティの有効化が必要です
3. 割り込みにより切り詰められたレスポンスにはトランスクリプトがありません

## ツールによる委譲

![Delegation through tools](https://cdn.openai.com/API/docs/diagram-speech-to-speech-agent-tools.png)

会話履歴とツール呼び出しを組み合わせることで、より複雑なアクションを実行するために会話を別のバックエンド エージェント に委譲し、その結果を ユーザー に返すことができます。

<Code lang="typescript" code={delegationAgentExample} />

以下のコードは サーバー 上で実行されます。この例では、Next.js の Server Actions を使用しています。

<Code lang="typescript" code={serverAgentExample} />
